#include "irm.h"


using namespace std;

namespace ophies {



// dcm_studies
DcmStudy::DcmStudy(QObject *parent)
:DataModel(ophies::DCM_STUDY, parent)
{
}

DcmStudy::~DcmStudy()
{
}


// dcm_series
DcmSeries::DcmSeries(QObject *parent)
:DataModel(ophies::DCM_SERIES, parent)
{
}

DcmSeries::~DcmSeries()
{
}

// dcm_instances
DcmInstance::DcmInstance(QObject *parent)
:DataModel(ophies::DCM_INSTANCE, parent)
{
}

DcmInstance::~DcmInstance()
{
}

// docsets
Docset::Docset(QObject *parent)
:DataModel(ophies::DOCSET, parent)
{
}

Docset::~Docset()
{
}

// patients
Patient::Patient(QObject *parent)
:DataModel(PATIENT, parent)
{
}

Patient::~Patient()
{
}

const char* DataModel::ATTRS_PATIENT[PAITNET_ATTR_COUNT] = { "patient_key",
                                            "patient_id_value",
                                            "patient_name",
                                            "patient_sex",
                                            "patient_birth_dttm",
                                            "related_patient_key",
                                            "created_dttm",
                                            "deleted_dttm",
                                            "url"};
const char* DataModel::ATTRS_DCM_STUDY[DCM_STUDY_ATTR_COUNT] = {  "dcm_study_key",
                                                "vgroup_key",
                                                "study_instance_uid",
                                                "patient_key",
                                                "patient_id",
                                                "patient_name",
                                                "patient_sex",
                                                "patient_birth_dttm",
                                                "patient_age",
                                                "patient_weight",
                                                "patient_size",
                                                "study_id",
                                                "study_dttm",
                                                "accession_no",
                                                "study_desc",
                                                "study_size",
                                                "series_count",
                                                "instance_count",
                                                "created_dttm",
                                                "updated_dttm",
                                                "deleted_dttm",
                                                "url"};
const char* DataModel::ATTRS_DCM_SERIES[DCM_SERIES_ATTR_COUNT] = {"dcm_series_key",
                                                "vgroup_key",
                                                "series_instance_uid",
                                                "dcm_study_key",
                                                "modality",
                                                "series_no",
                                                "series_dttm",
                                                "series_desc",
                                                "bodypart",
                                                "series_size",
                                                "instance_count",
                                                "created_dttm",
                                                "deleted_dttm",
                                               "url"};
const char* DataModel::ATTRS_DCM_INSTANCE[DCM_INSTANCE_ATTR_COUNT] = {
												"dcm_instance_key",
                                               "vgroup_key",
                                               "sop_instance_uid",
                                               "sop_class_uid",
                                               "dcm_series_key",
                                               "dcm_study_key",
                                               "instance_no",
                                               "content_dttm",
                                               "instance_size",
                                               "created_dttm",
                                               "deleted_dttm",
                                               "url"};

const char* DataModel::ATTRS_DOCSET[DOCSET_ATTR_COUNT] = {"docset_key",
                                         "vgroup_key",
                                         "vgroup_id",
                                         "vgroup_id_type",
                                         "vgroup_name",
                                         "docset_uid",
                                         "docset_class_uid",
                                         "docset_group_uid",
                                         "filter_key",
                                         "filter_uid",
                                         "filter_class_uid",
                                         "filter_name",
                                         "patient_key",
                                         "patient_id_value",
                                         "patient_name",
                                         "docset_created_dttm",
                                         "docset_deleted_dttm",
                                         "xds_docset_key",
                                         "metadata_xml",
                                         "docset_uuid",
                                         "source_id",
                                         "content_type_code_value",
                                         "content_type_coding_scheme",
                                         "content_type_code_meaning",
                                         "docset_status",
                                         "docset_title",
                                         "docset_comments",
                                         "submit_dttm",
                                         "xds_docset_created_dttm",
                                         "xds_docset_deleted_dttm",
                                         "document_count",
                                         "url"};

DataModel::DataModel(DataModelType type, QObject *parent) :
    QObject(parent),
    m_type(type),
    m_attributes(new QHash<QString, QString>()),
	m_dcm_children(new QList<DataModel*>()),
	m_wado_urls(new QList<QString>())
{
}

DataModel::~DataModel()
{
    std::cout << "data model destroyed" << std::endl;
	for(int i = 0; i < m_attributes->keys().size(); i++)
	{
		m_attributes->remove(m_attributes->keys().at(i));
	}
    delete m_attributes;
	
	for(int i = 0; i < m_dcm_children->count(); i++)
	{
		m_dcm_children->removeAt(i);
	}
	delete m_dcm_children;

	delete m_wado_urls;
}

bool DataModel::save()
{
    onSave();
    return false;
}

void DataModel::onSave()
{

}

QList<QString>* DataModel::get_wado_urls()
{
	return m_wado_urls;
}

QString DataModel::get_wado_url(QString series_instance_uid, QString sop_instance_uid)
{
	for(int i = 0; i < m_wado_urls->size(); i++ )
	{
		if( m_wado_urls->at(i).contains(series_instance_uid) &&
			m_wado_urls->at(i).contains(sop_instance_uid) )
		{
			return m_wado_urls->at(i);
		}
	}

	return "error";
}

QList<QString>* DataModel::get_download_urls()
{
	return m_download_urls;
}

QString DataModel::get_download_url(QString sop_instance_uid)
{
	for(int i = 0; i < m_wado_urls->size(); i++ )
	{
		if( m_wado_urls->at(i).contains(sop_instance_uid) )
		{
			return m_wado_urls->at(i);
		}
	}

	return "error";
}

void DataModel::download_all_instances(QString dirPath)
{
	QNetworkAccessManager *nm = new QNetworkAccessManager(this);
	connect(nm, SIGNAL(finished(QNetworkReply*)), 
		this, SLOT(onDcmReceived(QNetworkReply*)));

	QString prefix = "dcm_";
	if(getDataModelType() == DCM_STUDY)
	{
		prefix += m_attributes->value("study_instance_uid", "unknown_instance_uid");	
	}

	for( int i = 0; i < m_download_urls->size(); i++ )
	{
		// emit signal in non-blocking manner
		QUrl url(m_download_urls->at(i));
		QNetworkRequest request(url);
		((QObject*)&request)->setProperty("dir_path", dirPath);
		((QObject*)&request)->setProperty("file_name", QString("%s_%d").arg(prefix, i));
		nm->get(request);

	}

	nm->deleteLater();
}

void DataModel::onDcmReceived(QNetworkReply* reply)
{
	// no error received?
	if (reply->error() == QNetworkReply::NoError)
	{
		// read data from QNetworkReply here

		// Example 1: Creating QImage from the reply
		// QImageReader imageReader(reply);
		// QImage pic = imageReader.read();

		const int block_size = 1024*1024;
		int total_bytes_read = 0;
		int bytes_read = 0;
		char *tmp; //[block_size];
		QByteArray arr;

		QString dirPath = ((QObject*)&(reply->request()))->property("dir_path").toString();
		QString filename = ((QObject*)&(reply->request()))->property("file_name").toString();

		QFile file(QString("%s/%s").arg(dirPath, filename));
		file.open(QIODevice::WriteOnly);
		QDataStream out(&file);
		// Example 2: Reading bytes form the reply
		while(total_bytes_read < reply->bytesAvailable())
		{
			arr = reply->read(block_size);
			if ( bytes_read > 0)
			{
				tmp = arr.data();
				out.writeBytes(tmp, arr.size());
			}
		}
		file.close();
	}
	// Some http error received
	else
	{
		// handle errors here
	}

	delete reply;

	

}
/////////////////////////////////////////////////////////////////////////
/// \brief DataModel::fromJson
/// \param jsonStr
/////////////////////////////////////////////////////////////////////////
void DataModel::fromJson(QString jsonStr)
{
    Json::Value root;
    Json::Reader reader;

    bool result = reader.parse(jsonStr.toStdString(), root);
    if(!result)
    {
//         report to the user the failure and their locations in the document.
        std::cout  << "Failed to parse configuration\n"
                   << reader.getFormattedErrorMessages().c_str() << std::endl;
        return;
    }

    if(!root.isNull() && !root.isArray())
    {
        fromJson(root);
    }
}

/////////////////////////////////////////////////////////////////////////
/// \brief DataModel::fromJson
/// \param value
/////////////////////////////////////////////////////////////////////////
void DataModel::fromJson(Json::Value &value)
{
	Json::Value jvalue_array;
	Json::Value *jvalue_object;

    switch(m_type) {
    case PATIENT:
        for(int i = 0; i < PAITNET_ATTR_COUNT; i++)
        {
            setAttr(ATTRS_PATIENT[i],
                                 QString(value.get(ATTRS_PATIENT[i], "error").asString().c_str()));
        }
        break;
    case DCM_STUDY:;
        for(int i = 0; i < DCM_STUDY_ATTR_COUNT; i++)
        {
            setAttr(ATTRS_DCM_STUDY[i],
                                 QString(value.get(ATTRS_DCM_STUDY[i], "error").asString().c_str()));
			jvalue_array = value["wado_urls"];
			for( unsigned int i = 0; i < jvalue_array.size(); i++ )
			{
				m_wado_urls->append(QString(jvalue_array[i].asCString()));
			}

			jvalue_array = value["download_urls"];
			for( unsigned int i = 0; i < jvalue_array.size(); i++ )
			{
				m_download_urls->append(QString(jvalue_array[i].asCString()));
			}
        }
        break;
    case DCM_SERIES:
        for(int i = 0; i < DCM_SERIES_ATTR_COUNT; i++)
        {
            setAttr(ATTRS_DCM_SERIES[i],
                                 QString(value.get(ATTRS_DCM_SERIES[i], "error").asString().c_str()));
			
        }

		// append instances if exists
		//jvalue_array = &value["dcm_instances"];
		//if( jvalue_array && jvalue_array->isArray() )
		//{
		//	for( int i = 0; i < jvalue_array->size(); i++ )
		//	{
		//		jvalue_object = &jvalue_array[i];
		//		DcmInstance *tmp = new DcmInstance( parent() );
		//		tmp->fromJson( *jvalue_object );
		//		m_dcm_children->append( tmp );
		//	}
		//}
        break;
    case DCM_INSTANCE:
        for(int i = 0; i < DCM_INSTANCE_ATTR_COUNT; i++)
        {
            setAttr(ATTRS_DCM_INSTANCE[i],
                                 QString(value.get(ATTRS_DCM_INSTANCE[i], "error").asString().c_str()));
        }
        break;
    case DOCSET:
        for(int i = 0; i < DOCSET_ATTR_COUNT; i++)
        {
            setAttr(ATTRS_DOCSET[i],
                                 QString(value.get(ATTRS_DOCSET[i], "error").asString().c_str()));
        }
        break;
    default:
        break;
    }

}

QString DataModel::getAttr(QString attr_name, QString defaultValue)
{
    return m_attributes->value(attr_name, defaultValue);
}

void DataModel::setAttr(QString attr_name, QString value)
{
    m_attributes->insert(attr_name, value);
}

DataModelType DataModel::getDataModelType()
{
	return m_type;
}





}




